// Common/MyString.cpp
#include "stdafx.h"

#define MY_STRING_NEW(_T_, _size_) new _T_[_size_]
// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_)))

/*
inline const char* MyStringGetNextCharPointer(const char *p) throw()
{
#if defined(_WIN32) && !defined(UNDER_CE)
return CharNextA(p);
#else
return p + 1;
#endif
}
*/

int FindCharPosInString(const char *s, char c) throw()
{
	for (const char *p = s;; p++)
	{
		if (*p == c)
			return (int)(p - s);
		if (*p == 0)
			return -1;
		// MyStringGetNextCharPointer(p);
	}
}

int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
{
	for (const wchar_t *p = s;; p++)
	{
		if (*p == c)
			return (int)(p - s);
		if (*p == 0)
			return -1;
	}
}

/*
void MyStringUpper_Ascii(wchar_t *s)
{
for (;;)
{
wchar_t c = *s;
if (c == 0)
return;
*s++ = MyCharUpper_Ascii(c);
}
}
*/

void MyStringLower_Ascii(wchar_t *s) throw()
{
	for (;;)
	{
		wchar_t c = *s;
		if (c == 0)
			return;
		*s++ = MyCharLower_Ascii(c);
	}
}

#ifdef _WIN32

#ifdef _UNICODE

// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
// for WinCE - FString - char
// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; }

#else

// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); }
// char * MyStringUpper(char *s) { return CharUpperA(s); }
// char * MyStringLower(char *s) { return CharLowerA(s); }

wchar_t MyCharUpper_WIN(wchar_t c) throw()
{
	wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
	if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
		return (wchar_t)(unsigned)(UINT_PTR)res;
	const int kBufSize = 4;
	char s[kBufSize + 1];
	int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
	if (numChars == 0 || numChars > kBufSize)
		return c;
	s[numChars] = 0;
	::CharUpperA(s);
	::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
	return c;
}

/*
wchar_t MyCharLower_WIN(wchar_t c)
{
wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
return (wchar_t)(unsigned)(UINT_PTR)res;
const int kBufSize = 4;
char s[kBufSize + 1];
int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
if (numChars == 0 || numChars > kBufSize)
return c;
s[numChars] = 0;
::CharLowerA(s);
::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
return c;
}
*/

/*
wchar_t * MyStringUpper(wchar_t *s)
{
if (s == 0)
return 0;
wchar_t *res = CharUpperW(s);
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
return res;
AString a = UnicodeStringToMultiByte(s);
a.MakeUpper();
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
return s;
}
*/

/*
wchar_t * MyStringLower(wchar_t *s)
{
if (s == 0)
return 0;
wchar_t *res = CharLowerW(s);
if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
return res;
AString a = UnicodeStringToMultiByte(s);
a.MakeLower();
MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
return s;
}
*/

#endif


bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
{
	for (;;)
	{
		unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
		unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
	}
}

#endif
bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
{
	for (;;)
	{
		wchar_t c1 = *s1++;
		wchar_t c2 = *s2++;
		if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
		if (c1 == 0) return true;
	}
}

#ifdef ASTRING
// ---------- ASCII ----------

bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
{
	const char *s1 = _chars;
	for (;;)
	{
		char c2 = *s++;
		if (c2 == 0)
			return true;
		char c1 = *s1++;
		if (MyCharLower_Ascii(c1) !=
			MyCharLower_Ascii(c2))
			return false;
	}
}
#endif

bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
{
	const wchar_t *s1 = _chars;
	for (;;)
	{
		char c2 = *s++;
		if (c2 == 0)
			return true;
		wchar_t c1 = *s1++;
		if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
			return false;
	}
}

bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
{
	for (;;)
	{
		unsigned char c = *a;
		if (c != *u)
			return false;
		if (c == 0)
			return true;
		a++;
		u++;
	}
}

bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
{
	for (;;)
	{
		char c1 = *s1++;
		char c2 = *s2++;
		if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
			return false;
		if (c1 == 0)
			return true;
	}
}

bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
{
	for (;;)
	{
		wchar_t c1 = *s1++;
		wchar_t c2 = *s2++;
		if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
			return false;
		if (c1 == 0)
			return true;
	}
}

bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
{
	for (;;)
	{
		wchar_t c1 = *s1++;
		char c2 = *s2++;
		if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
			return false;
		if (c1 == 0)
			return true;
	}
}

bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
{
	for (;;)
	{
		wchar_t c2 = *s2++; if (c2 == 0) return true;
		wchar_t c1 = *s1++; if (c1 != c2) return false;
	}
}

// NTFS order: uses upper case
int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
{
	for (;;)
	{
		wchar_t c1 = *s1++;
		wchar_t c2 = *s2++;
		if (c1 != c2)
		{
			wchar_t u1 = MyCharUpper(c1);
			wchar_t u2 = MyCharUpper(c2);
			if (u1 < u2) return -1;
			if (u1 > u2) return 1;
		}
		if (c1 == 0) return 0;
	}
}

int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw()
{
	for (; num != 0; num--)
	{
		wchar_t c1 = *s1++;
		wchar_t c2 = *s2++;
		if (c1 != c2)
		{
			wchar_t u1 = MyCharUpper(c1);
			wchar_t u2 = MyCharUpper(c2);
			if (u1 < u2) return -1;
			if (u1 > u2) return 1;
		}
		if (c1 == 0) return 0;
	}
	return 0;
}

#ifdef ASTRING 

// ---------- AString ----------

void AString::InsertSpace(unsigned &index, unsigned size)
{
	Grow(size);
	MoveItems(index + size, index);
}

void AString::ReAlloc(unsigned newLimit)
{
	if (newLimit < _len || newLimit >= 0x20000000) throw 20130220;
	// MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1);
	char *newBuf = MY_STRING_NEW(char, newLimit + 1);
	memcpy(newBuf, _chars, (size_t)(_len + 1)); \
		MY_STRING_DELETE(_chars);
	_chars = newBuf;

	_limit = newLimit;
}

void AString::SetStartLen(unsigned len)
{
	_chars = 0;
	_chars = MY_STRING_NEW(char, len + 1);
	_len = len;
	_limit = len;
}

void AString::Grow_1()
{
	unsigned next = _len;
	next += next / 2;
	next += 16;
	next &= ~(unsigned)15;
	ReAlloc(next - 1);
}

void AString::Grow(unsigned n)
{
	unsigned freeSize = _limit - _len;
	if (n <= freeSize)
		return;

	unsigned next = _len + n;
	next += next / 2;
	next += 16;
	next &= ~(unsigned)15;
	ReAlloc(next - 1);
}

/*
AString::AString(unsigned num, const char *s)
{
unsigned len = MyStringLen(s);
if (num > len)
num = len;
SetStartLen(num);
memcpy(_chars, s, num);
_chars[num] = 0;
}
*/

AString::AString(unsigned num, const AString &s)
{
	if (num > s._len)
		num = s._len;
	SetStartLen(num);
	memcpy(_chars, s._chars, num);
	_chars[num] = 0;
}

AString::AString(const AString &s, char c)
{
	SetStartLen(s.Len() + 1);
	char *chars = _chars;
	unsigned len = s.Len();
	memcpy(chars, s, len);
	chars[len] = c;
	chars[len + 1] = 0;
}

AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
{
	SetStartLen(num1 + num2);
	char *chars = _chars;
	memcpy(chars, s1, num1);
	memcpy(chars + num1, s2, num2 + 1);
}

AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
AString operator+(const AString &s1, const char    *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
AString operator+(const char    *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }

AString::AString()
{
	_chars = 0;
	_chars = MY_STRING_NEW(char, 4);
	_len = 0;
	_limit = 4 - 1;
	_chars[0] = 0;
}

AString::AString(char c)
{
	SetStartLen(1);
	_chars[0] = c;
	_chars[1] = 0;
}

AString::AString(const char *s)
{
	SetStartLen(MyStringLen(s));
	MyStringCopy(_chars, s);
}

AString::AString(const AString &s)
{
	SetStartLen(s._len);
	MyStringCopy(_chars, s._chars);
}

AString &AString::operator=(char c)
{
	if (1 > _limit)
	{
		char *newBuf = MY_STRING_NEW(char, 1 + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = 1;
	}
	_len = 1;
	_chars[0] = c;
	_chars[1] = 0;
	return *this;
}

AString &AString::operator=(const char *s)
{
	unsigned len = MyStringLen(s);
	if (len > _limit)
	{
		char *newBuf = MY_STRING_NEW(char, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	_len = len;
	MyStringCopy(_chars, s);
	return *this;
}

AString &AString::operator=(const AString &s)
{
	if (&s == this)
		return *this;
	unsigned len = s._len;
	if (len > _limit)
	{
		char *newBuf = MY_STRING_NEW(char, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	_len = len;
	MyStringCopy(_chars, s._chars);
	return *this;
}

AString &AString::operator+=(const char *s)
{
	unsigned len = MyStringLen(s);
	Grow(len);
	MyStringCopy(_chars + _len, s);
	_len += len;
	return *this;
}

AString &AString::operator+=(const AString &s)
{
	Grow(s._len);
	MyStringCopy(_chars + _len, s._chars);
	_len += s._len;
	return *this;
}

void AString::SetFrom(const char *s, unsigned len) // no check
{
	if (len > _limit)
	{
		char *newBuf = MY_STRING_NEW(char, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	memcpy(_chars, s, len);
	_chars[len] = 0;
	_len = len;
}

int AString::Find(const AString &s, unsigned startIndex) const throw()
{
	if (s.IsEmpty())
		return startIndex;
	for (; startIndex < _len; startIndex++)
	{
		unsigned j;
		for (j = 0; j < s._len && startIndex + j < _len; j++)
			if (_chars[startIndex + j] != s._chars[j])
				break;
		if (j == s._len)
			return (int)startIndex;
	}
	return -1;
}

int AString::ReverseFind(char c) const throw()
{
	if (_len == 0)
		return -1;
	const char *p = _chars + _len - 1;
	for (;;)
	{
		if (*p == c)
			return (int)(p - _chars);
		if (p == _chars)
			return -1;
		p--; // p = GetPrevCharPointer(_chars, p);
	}
}

void AString::TrimLeft() throw()
{
	const char *p = _chars;
	for (;; p++)
	{
		char c = *p;
		if (c != ' ' && c != '\n' && c != '\t')
			break;
	}
	unsigned pos = (unsigned)(p - _chars);
	if (pos != 0)
	{
		MoveItems(0, pos);
		_len -= pos;
	}
}

void AString::TrimRight() throw()
{
	const char *p = _chars;
	int i;
	for (i = _len - 1; i >= 0; i--)
	{
		char c = p[i];
		if (c != ' ' && c != '\n' && c != '\t')
			break;
	}
	i++;
	if ((unsigned)i != _len)
	{
		_chars[i] = 0;
		_len = i;
	}
}

void AString::InsertAtFront(char c)
{
	if (_limit == _len)
		Grow_1();
	MoveItems(1, 0);
	_chars[0] = c;
	_len++;
}

/*
void AString::Insert(unsigned index, char c)
{
InsertSpace(index, 1);
_chars[index] = c;
_len++;
}
*/

void AString::Insert(unsigned index, const char *s)
{
	unsigned num = MyStringLen(s);
	if (num != 0)
	{
		InsertSpace(index, num);
		memcpy(_chars + index, s, num);
		_len += num;
	}
}

void AString::Insert(unsigned index, const AString &s)
{
	unsigned num = s.Len();
	if (num != 0)
	{
		InsertSpace(index, num);
		memcpy(_chars + index, s, num);
		_len += num;
	}
}

void AString::RemoveChar(char ch) throw()
{
	int pos = Find(ch);
	if (pos < 0)
		return;
	const char *src = _chars;
	char *dest = _chars + pos;
	pos++;
	unsigned len = _len;
	for (; (unsigned)pos < len; pos++)
	{
		char c = src[(unsigned)pos];
		if (c != ch)
			*dest++ = c;
	}
	*dest = 0;
	_len = (unsigned)(dest - _chars);
}

// !!!!!!!!!!!!!!! test it if newChar = '\0'
void AString::Replace(char oldChar, char newChar) throw()
{
	if (oldChar == newChar)
		return; // 0;
	// unsigned number = 0;
	int pos = 0;
	while ((unsigned)pos < _len)
	{
		pos = Find(oldChar, pos);
		if (pos < 0)
			break;
		_chars[pos] = newChar;
		pos++;
		// number++;
	}
	return; //  number;
}

void AString::Replace(const AString &oldString, const AString &newString)
{
	if (oldString.IsEmpty())
		return; // 0;
	if (oldString == newString)
		return; // 0;
	unsigned oldLen = oldString.Len();
	unsigned newLen = newString.Len();
	// unsigned number = 0;
	int pos = 0;
	while ((unsigned)pos < _len)
	{
		pos = Find(oldString, pos);
		if (pos < 0)
			break;
		Delete(pos, oldLen);
		Insert(pos, newString);
		pos += newLen;
		// number++;
	}
	// return number;
}

void AString::Delete(unsigned index) throw()
{
	MoveItems(index, index + 1);
	_len--;
}

void AString::Delete(unsigned index, unsigned count) throw()
{
	if (index + count > _len)
		count = _len - index;
	if (count > 0)
	{
		MoveItems(index, index + count);
		_len -= count;
	}
}

void AString::DeleteFrontal(unsigned num) throw()
{
	if (num != 0)
	{
		MoveItems(0, num);
		_len -= num;
	}
}

/*
AString operator+(const AString &s1, const AString &s2)
{
AString result(s1);
result += s2;
return result;
}

AString operator+(const AString &s, const char *chars)
{
AString result(s);
result += chars;
return result;
}

AString operator+(const char *chars, const AString &s)
{
AString result(chars);
result += s;
return result;
}

AString operator+(const AString &s, char c)
{
AString result(s);
result += c;
return result;
}
*/

/*
AString operator+(char c, const AString &s)
{
AString result(c);
result += s;
return result;
}
*/
#endif

// ---------- UString ----------

void UString::InsertSpace(unsigned index, unsigned size)
{
	Grow(size);
	MoveItems(index + size, index);
}

void UString::ReAlloc(unsigned newLimit)
{
	if (newLimit < _len || newLimit >= 0x20000000) throw 20130221;
	// MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1);
	wchar_t *newBuf = MY_STRING_NEW(wchar_t, newLimit + 1);
	wmemcpy(newBuf, _chars, _len + 1);
	MY_STRING_DELETE(_chars);
	_chars = newBuf;

	_limit = newLimit;
}

void UString::SetStartLen(unsigned len)
{
	_chars = 0;
	_chars = MY_STRING_NEW(wchar_t, len + 1);
	_len = len;
	_limit = len;
}

void UString::Grow_1()
{
	unsigned next = _len;
	next += next / 2;
	next += 16;
	next &= ~(unsigned)15;
	ReAlloc(next - 1);
}

void UString::Grow(unsigned n)
{
	unsigned freeSize = _limit - _len;
	if (n <= freeSize)
		return;

	unsigned next = _len + n;
	next += next / 2;
	next += 16;
	next &= ~(unsigned)15;
	ReAlloc(next - 1);
}


UString::UString(unsigned num, const wchar_t *s)
{
	unsigned len = MyStringLen(s);
	if (num > len)
		num = len;
	SetStartLen(num);
	wmemcpy(_chars, s, num);
	_chars[num] = 0;
}


UString::UString(unsigned num, const UString &s)
{
	if (num > s._len)
		num = s._len;
	SetStartLen(num);
	wmemcpy(_chars, s._chars, num);
	_chars[num] = 0;
}

UString::UString(const UString &s, wchar_t c)
{
	SetStartLen(s.Len() + 1);
	wchar_t *chars = _chars;
	unsigned len = s.Len();
	wmemcpy(chars, s, len);
	chars[len] = c;
	chars[len + 1] = 0;
}

UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
{
	SetStartLen(num1 + num2);
	wchar_t *chars = _chars;
	wmemcpy(chars, s1, num1);
	wmemcpy(chars + num1, s2, num2 + 1);
}

UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }

UString::UString()
{
	_chars = 0;
	_chars = MY_STRING_NEW(wchar_t, 4);
	_len = 0;
	_limit = 4 - 1;
	_chars[0] = 0;
}

UString::UString(wchar_t c)
{
	SetStartLen(1);
	_chars[0] = c;
	_chars[1] = 0;
}

UString::UString(const wchar_t *s)
{
	SetStartLen(MyStringLen(s));
	MyStringCopy(_chars, s);
}

UString::UString(const UString &s)
{
	SetStartLen(s._len);
	MyStringCopy(_chars, s._chars);
}

UString::~UString()
{
	MY_STRING_DELETE(_chars);
	//if (_chars) 
	//{
	//	delete [] _chars;
	//	_chars = NULL;
	//}
}

TCHAR UString::GetAt(int nIndex) const
{
	TCHAR ch = NULL;
	if (nIndex < _len)
		ch = _chars[nIndex];
	return ch;
}

TCHAR UString::operator[] (int nIndex) const
{
	return GetAt(nIndex);
}

//bool UString::operator == (LPCTSTR str) const { return (Compare(str) == 0); };
bool UString::operator != (LPCTSTR str) const { return (Compare(str) != 0); };
bool UString::operator <= (LPCTSTR str) const { return (Compare(str) <= 0); };
bool UString::operator <  (LPCTSTR str) const { return (Compare(str) < 0); };
bool UString::operator >= (LPCTSTR str) const { return (Compare(str) >= 0); };
bool UString::operator >  (LPCTSTR str) const { return (Compare(str) > 0); };


UString &UString::operator=(wchar_t c)
{
	if (1 > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, 1 + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = 1;
	}
	_len = 1;
	_chars[0] = c;
	_chars[1] = 0;
	return *this;
}

UString &UString::operator=(const char *s)
{
	wstring str = C2W(s);
	unsigned len = str.length();
	if (len > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	_len = len;
	MyStringCopy(_chars, str.c_str());
	return *this;
}

UString &UString::operator=(const wchar_t *s)
{
	unsigned len = MyStringLen(s);
	if (len > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	_len = len;
	MyStringCopy(_chars, s);
	return *this;
}

UString &UString::operator=(const UString &s)
{
	if (&s == this)
		return *this;
	unsigned len = s._len;
	if (len > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	_len = len;
	MyStringCopy(_chars, s._chars);
	return *this;
}

UString &UString::operator+=(const wchar_t *s)
{
	unsigned len = MyStringLen(s);
	Grow(len);
	MyStringCopy(_chars + _len, s);
	_len += len;
	return *this;
}


UString &UString::operator+=(const UString &s)
{
	Grow(s._len);
	MyStringCopy(_chars + _len, s._chars);
	_len += s._len;
	return *this;
}

void UString::SetFrom(const wchar_t *s, unsigned len) // no check
{
	if (len > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	wmemcpy(_chars, s, len);
	_chars[len] = 0;
	_len = len;
}

void UString::SetFromAscii(const char *s)
{
	unsigned len = MyStringLen(s);
	if (len > _limit)
	{
		wchar_t *newBuf = MY_STRING_NEW(wchar_t, len + 1);
		MY_STRING_DELETE(_chars);
		_chars = newBuf;
		_limit = len;
	}
	wchar_t *chars = _chars;
	for (unsigned i = 0; i < len; i++)
		chars[i] = s[i];
	chars[len] = 0;
	_len = len;
}

void UString::AddAsciiStr(const char *s)
{
	unsigned len = MyStringLen(s);
	Grow(len);
	wchar_t *chars = _chars + _len;
	for (unsigned i = 0; i < len; i++)
		chars[i] = s[i];
	chars[len] = 0;
	_len += len;
}



int UString::Find(const UString &s, unsigned startIndex) const throw()
{
	if (s.IsEmpty())
		return startIndex;
	for (; startIndex < _len; startIndex++)
	{
		unsigned j;
		for (j = 0; j < s._len && startIndex + j < _len; j++)
			if (_chars[startIndex + j] != s._chars[j])
				break;
		if (j == s._len)
			return (int)startIndex;
	}
	return -1;
}

int UString::ReverseFind(wchar_t c) const throw()
{
	if (_len == 0)
		return -1;
	const wchar_t *p = _chars + _len - 1;
	for (;;)
	{
		if (*p == c)
			return (int)(p - _chars);
		if (p == _chars)
			return -1;
		p--;
	}
}

void UString::Append(const wchar_t * s)
{
	unsigned len = MyStringLen(s);
	Grow(len);
	MyStringCopy(_chars + _len, s);
	_len += len;
}

void UString::Format(LPCTSTR wszPrintString, ...) throw()
{
	if (wszPrintString == NULL) return;
	va_list arg_list;
	int len;
	WCHAR * wszFinalString;
	va_start(arg_list, wszPrintString);
	len = _vscwprintf(wszPrintString, arg_list) + 1;
	wszFinalString = (WCHAR *)malloc(len * sizeof(WCHAR));
	vswprintf_s(wszFinalString, len, wszPrintString, arg_list);
	va_end(arg_list);
	SetStartLen(len);
	MyStringCopy(_chars, wszFinalString);
	free(wszFinalString);
	wszFinalString = NULL;
}

void UString::AppendFormat(LPCTSTR wszPrintString, ...) throw()
{
	if (wszPrintString == NULL) return;
	va_list arg_list;
	int len;
	WCHAR * wszFinalString;
	va_start(arg_list, wszPrintString);
	len = _vscwprintf(wszPrintString, arg_list) + 1;
	wszFinalString = (WCHAR *)malloc(len * sizeof(WCHAR));
	vswprintf_s(wszFinalString, len, wszPrintString, arg_list);
	va_end(arg_list);
	Append(wszFinalString);
	free(wszFinalString);
	wszFinalString = NULL;
}

void UString::TrimLeft() throw()
{
	const wchar_t *p = _chars;
	for (;; p++)
	{
		wchar_t c = *p;
		if (c != ' ' && c != '\n' && c != '\t')
			break;
	}
	unsigned pos = (unsigned)(p - _chars);
	if (pos != 0)
	{
		MoveItems(0, pos);
		_len -= pos;
	}
}

void UString::TrimRight() throw()
{
	const wchar_t *p = _chars;
	int i;
	for (i = _len - 1; i >= 0; i--)
	{
		wchar_t c = p[i];
		if (c != ' ' && c != '\n' && c != '\t')
			break;
	}
	i++;
	if ((unsigned)i != _len)
	{
		_chars[i] = 0;
		_len = i;
	}
}

void UString::InsertAtFront(wchar_t c)
{
	if (_limit == _len)
		Grow_1();
	MoveItems(1, 0);
	_chars[0] = c;
	_len++;
}

/*
void UString::Insert(unsigned index, wchar_t c)
{
InsertSpace(index, 1);
_chars[index] = c;
_len++;
}
*/

void UString::Insert(unsigned index, const wchar_t *s)
{
	unsigned num = MyStringLen(s);
	if (num != 0)
	{
		InsertSpace(index, num);
		wmemcpy(_chars + index, s, num);
		_len += num;
	}
}

void UString::Insert(unsigned index, const UString &s)
{
	unsigned num = s.Len();
	if (num != 0)
	{
		InsertSpace(index, num);
		wmemcpy(_chars + index, s, num);
		_len += num;
	}
}

void UString::RemoveChar(wchar_t ch) throw()
{
	int pos = Find(ch);
	if (pos < 0)
		return;
	const wchar_t *src = _chars;
	wchar_t *dest = _chars + pos;
	pos++;
	unsigned len = _len;
	for (; (unsigned)pos < len; pos++)
	{
		wchar_t c = src[(unsigned)pos];
		if (c != ch)
			*dest++ = c;
	}
	*dest = 0;
	_len = (unsigned)(dest - _chars);
}

// !!!!!!!!!!!!!!! test it if newChar = '\0'
void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
{
	if (oldChar == newChar)
		return; // 0;
	// unsigned number = 0;
	int pos = 0;
	while ((unsigned)pos < _len)
	{
		pos = Find(oldChar, pos);
		if (pos < 0)
			break;
		_chars[pos] = newChar;
		pos++;
		// number++;
	}
	return; //  number;
}

void UString::Replace(const UString &oldString, const UString &newString)
{
	if (oldString.IsEmpty())
		return; // 0;
	if (oldString == newString)
		return; // 0;
	unsigned oldLen = oldString.Len();
	unsigned newLen = newString.Len();
	// unsigned number = 0;
	int pos = 0;
	while ((unsigned)pos < _len)
	{
		pos = Find(oldString, pos);
		if (pos < 0)
			break;
		Delete(pos, oldLen);
		Insert(pos, newString);
		pos += newLen;
		// number++;
	}
	// return number;
}

void UString::Delete(unsigned index) throw()
{
	MoveItems(index, index + 1);
	_len--;
}

void UString::Delete(unsigned index, unsigned count) throw()
{
	if (index + count > _len)
		count = _len - index;
	if (count > 0)
	{
		MoveItems(index, index + count);
		_len -= count;
	}
}

void UString::DeleteFrontal(unsigned num) throw()
{
	if (num != 0)
	{
		MoveItems(0, num);
		_len -= num;
	}
}

const char * UString::GetStringA()
{
	return W2A(_chars).c_str();
}

//const char * UString::operator()  const
//{
//	return W2A(_chars).c_str();
//}
// ----------------------------------------

/*
int MyStringCompareNoCase(const char *s1, const char *s2)
{
return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
}
*/

static inline UINT GetCurrentCodePage()
{
#if defined(UNDER_CE) || !defined(_WIN32)
	return CP_ACP;
#else
	return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
#endif
}

